In this note, we study immigrants using OECD data and migrants using UN data. We also combine these two sets of data to provide examples to use public data.

Setup

Install a package countrycode first.

library(tidyverse)
library(WDI)
library(readxl)
library(countrycode)

OECD data

OECD data top

OECD data https://data.oecd.org/

  • Browse by Topics (Choose from 12 topics) or Country (Choose from 37 countries)
  • Topics:
    • Agriculture,
    • Development,
    • Economy,
    • Education,
    • Energy,
    • Environment,
    • Finance,
    • Government,
    • Health,
    • Innovation and Technology,
    • Jobs,
    • Society
      • Demography
      • Inequality
      • Migration
      • Population by Region
      • Social protection
  • Countries:
    • Australia, Austria, Belgium, Brazil, Canada, Chili, People’s Republic of China, Columbia, Costa Rica, Czechia, Denmark, Estonia, Finland, France, Germany, Greece, Hungary, Iceland, India, Indonesia, Ireland, Islael, Italy, Japan, Korea, Latvia, Lithuania, Luxembourg, Mexico, Netherlands, New Zealand, Norway, Poland, Portugal, Russian Federation, Slovak Republic, Slovenia, South Africa, Spain, Sweden, Swizerland, Türkiye, United Kingdom, United States

Database Access: https://data-explorer.oecd.org/

There is a newly developed Database Access linked above. However, it is still under development and difficult to handle data there.

Topic: Society - Migration

  • Permanent immigrant inflows
    • Permanent immigrant inflows cover regulated movements of foreigners considered to be settling in the country from the perspective of the destination country. They cover regulated movements of foreigners as well as free movement migration. The data presented are the result of a standardisation process that allows for cross-country comparisons. This indicator is measured by numbers of permanent inflows.
  • Stocks of foreign-born population in OECD countries
  • Foreign-born population
  • Foreign population
  • Native-born employment
  • Foreign-born employment
  • Native-born unemployment
  • Foreign-born unemployment
  • Native-born participation rates
  • Foreign-born participation rates

Permanent immigrant inflows

Permanent immigrant inflows Total, Number, 2022 Link

Definition of Permanent immigrant inflows

  • Permanent immigrant inflows cover regulated movements of foreigners considered to be settling in the country from the perspective of the destination country. They cover regulated movements of foreigners as well as free movement migration. The data presented are the result of a standardisation process that allows for cross-country comparisons. This indicator is measured by numbers of permanent inflows.
  • Citation: OECD (2024), Permanent immigrant inflows (indicator). doi: 10.1787/304546b6-en (Accessed on 27 January 2024)

OECD: Permanent immigrant inflows

Data Information

  • Data Site: https://data.oecd.org/migration/permanent-immigrant-inflows.htm

  • Definition of Permanent immigrant inflows: Permanent immigrant inflows cover regulated movements of foreigners considered to be settling in the country from the perspective of the destination country. They cover regulated movements of foreigners as well as free movement migration. The data presented are the result of a standardisation process that allows for cross-country comparisons. This indicator is measured by numbers of permanent inflows.

  • Citation: OECD (2024), Permanent immigrant inflows (indicator). doi: 10.1787/304546b6-en (Accessed on 28 January 2024)

  • Categories: Total, Work, Free movements, Family, Family accompanying workers, Humanitarian, Other

library(tidyverse)

Read the downloaded full data of ‘Permanent Immigrant Inflows’.

df_inflows <- read_csv("data/DP_LIVE_28012024004117279.csv")
Rows: 3597 Columns: 8── Column specification ─────────────────────────────────────────────────────────────────
Delimiter: ","
chr (5): LOCATION, INDICATOR, SUBJECT, MEASURE, FREQUENCY
dbl (2): TIME, Value
lgl (1): Flag Codes
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
df_inflows
df_inflows |> select(-Value) |> lapply(unique)
$LOCATION
 [1] "AUS" "AUT" "BEL" "CAN" "DNK" "FIN" "FRA" "DEU" "IRL" "ITA" "JPN" "KOR" "NLD" "NZL"
[15] "NOR" "PRT" "ESP" "SWE" "CHE" "GBR" "USA" "ISR" "RUS" "MEX" "CZE" "LUX" "POL" "EST"

$INDICATOR
[1] "IMMIGINFLOW"

$SUBJECT
[1] "FAM"      "FAMWORKR" "FREEMOVS" "HUMNTRN"  "OTH"      "WORK"     "TOT"     

$MEASURE
[1] "NBR"

$FREQUENCY
[1] "A"

$TIME
 [1] 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019
[18] 2020 2021 2022 2000 2001 2002 1995 1996 1997 1998 1999

$`Flag Codes`
[1] NA

Set the order of categories to display.

CAT <- c("TOT", "WORK", "FREEMOVS", "FAM", "FAMWORKR", "HUMNTRN", "OTH")

Add country names using the countrycode package and delete INDICATOR, MEASURE, FREQUENCY, Flag Codes.

df_in <- df_inflows |> 
  mutate(country = countrycode(LOCATION, "iso3c", "country.name"), .before = LOCATION) |> 
  select(country, iso3c = LOCATION, category = SUBJECT, year = TIME, value = Value)
df_in
df_in |> filter(country == "Japan") |> 
  ggplot(aes(year, value, col = factor(category, levels = CAT))) + geom_line() + 
  labs(col = "Categories")

df_in |> filter(country == "Japan") |> filter(category != "TOT") |> 
  ggplot(aes(year, value, fill = factor(category, levels = rev(CAT)))) + 
  geom_area(col = "black", linewidth = 0.1) +
  labs(title = "Permanent immigrant inflows of Japan", fill = "Categories")

df_in |> filter(category != "TOT") |> 
  ggplot(aes(year, value, fill = factor(category, levels = rev(CAT)))) + geom_area(col = "black", linewidth = 0.1) +
  facet_wrap(~country) + 
  labs(title = "Permanent immigrant inflows of 28 Countries", fill = "") +
  theme(legend.position = 'bottom')

df_in |> filter(country %in% c("Germany", "United States")) |> 
  ggplot(aes(year, value, col = country, linetype = factor(category, levels = CAT))) + geom_line() +
  labs(title = "Permanent immigrant inflows of Germany and United States", linetype = "Categories")

tot_lev <- df_in |> pivot_wider(names_from = category, values_from = value) |> 
  pivot_longer(cols = CAT[CAT!="TOT"], names_to = "category", values_to = "value") |> filter(year == 2022) |> distinct(country, iso3c, TOT) |> arrange(desc(TOT)) |> pull(country)
df_in |> pivot_wider(names_from = category, values_from = value) |> 
  pivot_longer(cols = CAT[CAT!="TOT"], names_to = "category", values_to = "value") |> filter(year == 2022) |> ggplot(aes(factor(country, levels = rev(tot_lev)), value, fill = factor(category, levels = CAT))) + geom_col(col = "black", linewidth = 0.1) + coord_flip() +
  labs(title = "Permanent immigrant inflows in 2022", fill = "", x = "") +
  theme(legend.position = 'bottom')

OECD: Foreign population

Data Information

  • Data Site: https://data.oecd.org/migration/foreign-population.htm

  • Definition of Foreign population: The foreign population consists of people who still have the nationality of their home country. It may include people born in the host country. The difference across countries between the size of the foreign-born population and that of the foreign population depends on the rules governing the acquisition of citizenship in each country. This indicator is measured as a percentage of population.

  • Citation: OECD (2024), Foreign population (indicator). doi: 10.1787/16a914e3-en (Accessed on 28 January 2024)

  • Categories: Total, Percent of Population

Read the downloaded full data of ‘Foreign population’.

df_foreign <- read_csv("data/DP_LIVE_28012024004200124.csv")
Rows: 545 Columns: 8── Column specification ─────────────────────────────────────────────────────────────────
Delimiter: ","
chr (5): LOCATION, INDICATOR, SUBJECT, MEASURE, FREQUENCY
dbl (2): TIME, Value
lgl (1): Flag Codes
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
df_foreign
df_foreign |> select(-Value) |> lapply(unique)
$LOCATION
 [1] "AUT" "BEL" "DNK" "FIN" "DEU" "HUN" "IRL" "ITA" "JPN" "KOR" "LUX" "NLD" "NOR" "PRT"
[15] "SVK" "SWE" "CHE" "GBR" "USA" "SVN" "CZE" "FRA" "POL" "ESP" "GRC" "EST" "ISL" "CAN"
[29] "MEX" "TUR" "CHL" "LVA" "LTU"

$INDICATOR
[1] "FPOP"

$SUBJECT
[1] "TOT"

$MEASURE
[1] "PC_POP"

$FREQUENCY
[1] "A"

$TIME
 [1] 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016
[18] 2017 2018 2019

$`Flag Codes`
[1] NA

Add country names using the countrycode package and delete INDICATOR, MEASURE, FREQUENCY, Flag Codes.

df_fpop <- df_foreign |> 
  mutate(country = countrycode(LOCATION, "iso3c", "country.name"), .before = LOCATION) |> 
  select(country, iso3c = LOCATION, year = TIME, foreign = Value)
df_fpop
df_fpop |> filter(country == "Japan") |> 
  ggplot(aes(year, foreign)) + geom_line() + 
  labs(title = "Foreign Population in Japan (Percent)")

df_fpop |> 
  ggplot(aes(year, foreign)) + geom_line(aes(col = iso3c)) + 
  geom_smooth(formula = 'y~x', method = "loess", se = FALSE) + 
  labs(title = "Total Foreign Population (%)")

df_fpop |> filter(year == 2019) |> 
  ggplot(aes(fct_reorder(country, foreign), foreign)) + geom_col() + 
  coord_flip() + labs(title = "Foreign Population (%)", x = "", y = "")

OECD: PopulationTotal, Million persons, 2022 or latest available

Data Information

  • Data Site: https://data.oecd.org/pop/population.htm

  • Definition of Population: Population is defined as all nationals present in, or temporarily absent from a country, and aliens permanently settled in a country. This indicator shows the number of people that usually live in an area. Growth rates are the annual changes in population resulting from births, deaths and net migration during the year. Total population includes the following: national armed forces stationed abroad; merchant seamen at sea; diplomatic personnel located abroad; civilian aliens resident in the country; displaced persons resident in the country. However, it excludes the following: foreign armed forces stationed in the country; foreign diplomatic personnel located in the country; civilian aliens temporarily in the country. Population projections are a common demographic tool. They provide a basis for other statistical projections, helping governments in their decision making. This indicator is measured in terms of annual growth rate and in thousands of people.

  • Citation: OECD (2024), Population (indicator). doi: 10.1787/d434f82b-en (Accessed on 28 January 2024)

df_oecd_pop <- read_csv("data/DP_LIVE_28012024064002957.csv")
Rows: 12264 Columns: 8── Column specification ─────────────────────────────────────────────────────────────────
Delimiter: ","
chr (5): LOCATION, INDICATOR, SUBJECT, MEASURE, FREQUENCY
dbl (2): TIME, Value
lgl (1): Flag Codes
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
df_oecd_pop
df_oecd_pop |> select(-Value) |> lapply(unique)
$LOCATION
 [1] "AUS"  "AUT"  "BEL"  "CAN"  "CZE"  "DNK"  "FIN"  "FRA"  "DEU"  "GRC"  "HUN"  "ISL" 
[13] "IRL"  "ITA"  "JPN"  "KOR"  "LUX"  "MEX"  "NLD"  "NZL"  "NOR"  "POL"  "PRT"  "SVK" 
[25] "ESP"  "SWE"  "CHE"  "TUR"  "GBR"  "USA"  "BRA"  "CHL"  "COL"  "EST"  "ISR"  "RUS" 
[37] "SVN"  "CHN"  "IND"  "IDN"  "ZAF"  "OECD" "LVA"  "ARG"  "BGR"  "CRI"  "HRV"  "CYP" 
[49] "LTU"  "MLT"  "ROU"  "SAU"  "SGP"  "WLD"  "G20"  "EU27"

$INDICATOR
[1] "POP"

$SUBJECT
[1] "MEN"   "TOT"   "WOMEN"

$MEASURE
[1] "MLN_PER"

$FREQUENCY
[1] "A"

$TIME
 [1] 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966
[18] 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983
[35] 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000
[52] 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017
[69] 2018 2019 2020 2021 2022

$`Flag Codes`
[1] NA
df_pop_short <- df_oecd_pop |> filter(SUBJECT == "TOT") |> select(iso3c = LOCATION, year = TIME, pop = Value)

Combine Three Datasets of OECD

Check the differences of countries in each datasets.

setdiff(df_fpop$iso3c, df_in$iso3c); setdiff(df_in$iso3c,df_fpop$iso3c)
[1] "HUN" "SVK" "SVN" "GRC" "ISL" "TUR" "CHL" "LVA" "LTU"
[1] "AUS" "NZL" "ISR" "RUS"
setdiff(df_fpop$iso3c, df_pop_short$iso3c); setdiff(df_in$iso3c, df_pop_short$iso3c)
character(0)
character(0)
  • “HUN” “SVK” “SVN” “GRC” “ISL” “TUR” “CHL” “LVA” “LTU” are in df_fpop but not in df_in.
  • “AUS” “NZL” “ISR” “RUS” are in df_in but not in df_fpop.
  • df_pop_short contains the data of countries in df_in and df_fpop.
df_fpop2 <- df_fpop |> select(iso3c, year, foreign)
df_oecd_fpop <- df_in |> full_join(df_fpop2, by = c("iso3c", "year")) |>
  left_join(df_pop_short, by = c("iso3c", "year")) |>
  mutate(foreign_pop = round(pop*10000*foreign), .after = value)
df_oecd_fpop
df_oecd_fpop |> filter(category == "TOT") |> drop_na(value, foreign) |>
  filter(value >0, foreign >0) |>
  ggplot(aes(value, foreign_pop)) + geom_point(aes(col = iso3c)) + scale_x_log10() + scale_y_log10() + geom_smooth(formula = 'y~x', method = "lm", se = FALSE)

UNdata - a world of information

https://data.un.org/

Popular statistical tables

Explorer - datamarts: http://data.un.org/Explorer.aspx

Join OECD Data with UN Data

df_oecd_un <- df_oecd_fpop |> left_join(df_un_migrants_ext_rev, by = c("country", "iso3c", "year")) |>
  select(country, iso3c, category, year, value, foreign_pop, foreign, pop, ser, migrants)
Warning: Detected an unexpected many-to-many relationship between `x` and `y`.
df_oecd_un
df_oecd_un |> filter(country == "Japan")
df_oecd_un_wide <- df_oecd_un |> drop_na(value, migrants) |> pivot_wider(names_from = category, values_from = value)  |>
  pivot_wider(names_from = ser, values_from = migrants)
df_oecd_un_wide
LS0tCnRpdGxlOiAiRm9yZWlnbmVycywgTWlncmFudHMgLSBPRUNEIGFuZCBVTiBkYXRhIgphdXRob3I6ICJJRCwgTGFzdCBOYW1lLCBGaXJzdCBOYW1lIgpkYXRlOiAiMjAyNC8wMS8yNCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OgogICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQoKPiBJbiB0aGlzIG5vdGUsIHdlIHN0dWR5IGltbWlncmFudHMgdXNpbmcgT0VDRCBkYXRhIGFuZCBtaWdyYW50cyB1c2luZyBVTiBkYXRhLiBXZSBhbHNvIGNvbWJpbmUgdGhlc2UgdHdvIHNldHMgb2YgZGF0YSB0byBwcm92aWRlIGV4YW1wbGVzIHRvIHVzZSBwdWJsaWMgZGF0YS4KCiMjIyBTZXR1cAoKSW5zdGFsbCBhIHBhY2thZ2UgYGNvdW50cnljb2RlYCBmaXJzdC4KCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShXREkpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KGNvdW50cnljb2RlKQpgYGAKCgojIyBPRUNEIGRhdGEKCiMjIyBPRUNEIGRhdGEgdG9wCgpPRUNEIGRhdGEgPGh0dHBzOi8vZGF0YS5vZWNkLm9yZy8+CiAgCiAgLSBCcm93c2UgYnkgVG9waWNzIChDaG9vc2UgZnJvbSAxMiB0b3BpY3MpIG9yIENvdW50cnkgKENob29zZSBmcm9tIDM3IGNvdW50cmllcykKICAtIFRvcGljczogCiAgICAtIEFncmljdWx0dXJlLCAKICAgIC0gRGV2ZWxvcG1lbnQsIAogICAgLSBFY29ub215LCAKICAgIC0gRWR1Y2F0aW9uLCAKICAgIC0gRW5lcmd5LCAKICAgIC0gRW52aXJvbm1lbnQsIAogICAgLSBGaW5hbmNlLCAKICAgIC0gR292ZXJubWVudCwgCiAgICAtIEhlYWx0aCwgCiAgICAtIElubm92YXRpb24gYW5kIFRlY2hub2xvZ3ksIAogICAgLSBKb2JzLCAKICAgIC0gU29jaWV0eQogICAgICAtIERlbW9ncmFwaHkKICAgICAgLSBJbmVxdWFsaXR5CiAgICAgIC0gTWlncmF0aW9uCiAgICAgIC0gUG9wdWxhdGlvbiBieSBSZWdpb24KICAgICAgLSBTb2NpYWwgcHJvdGVjdGlvbgogIC0gQ291bnRyaWVzOgogICAgLSBBdXN0cmFsaWEsIEF1c3RyaWEsIEJlbGdpdW0sIEJyYXppbCwgQ2FuYWRhLCBDaGlsaSwgUGVvcGxlJ3MgUmVwdWJsaWMgb2YgQ2hpbmEsIENvbHVtYmlhLCBDb3N0YSBSaWNhLCBDemVjaGlhLCBEZW5tYXJrLCBFc3RvbmlhLCBGaW5sYW5kLCBGcmFuY2UsIEdlcm1hbnksIEdyZWVjZSwgSHVuZ2FyeSwgSWNlbGFuZCwgSW5kaWEsIEluZG9uZXNpYSwgSXJlbGFuZCwgSXNsYWVsLCBJdGFseSwgSmFwYW4sIEtvcmVhLCBMYXR2aWEsIExpdGh1YW5pYSwgTHV4ZW1ib3VyZywgTWV4aWNvLCBOZXRoZXJsYW5kcywgTmV3IFplYWxhbmQsIE5vcndheSwgUG9sYW5kLCBQb3J0dWdhbCwgUnVzc2lhbiBGZWRlcmF0aW9uLCBTbG92YWsgUmVwdWJsaWMsIFNsb3ZlbmlhLCBTb3V0aCBBZnJpY2EsIFNwYWluLCBTd2VkZW4sIFN3aXplcmxhbmQsIFTDvHJraXllLCBVbml0ZWQgS2luZ2RvbSwgVW5pdGVkIFN0YXRlcyAKICAKCiMjIyMgRGF0YWJhc2UgQWNjZXNzOiA8aHR0cHM6Ly9kYXRhLWV4cGxvcmVyLm9lY2Qub3JnLz4KClRoZXJlIGlzIGEgbmV3bHkgZGV2ZWxvcGVkIERhdGFiYXNlIEFjY2VzcyBsaW5rZWQgYWJvdmUuIEhvd2V2ZXIsIGl0IGlzIHN0aWxsIHVuZGVyIGRldmVsb3BtZW50IGFuZCBkaWZmaWN1bHQgdG8gaGFuZGxlIGRhdGEgdGhlcmUuCgojIyMgVG9waWM6IFNvY2lldHkgLSBNaWdyYXRpb24KCi0gUGVybWFuZW50IGltbWlncmFudCBpbmZsb3dzCiAgLSBQZXJtYW5lbnQgaW1taWdyYW50IGluZmxvd3MgY292ZXIgcmVndWxhdGVkIG1vdmVtZW50cyBvZiBmb3JlaWduZXJzIGNvbnNpZGVyZWQgdG8gYmUgc2V0dGxpbmcgaW4gdGhlIGNvdW50cnkgZnJvbSB0aGUgcGVyc3BlY3RpdmUgb2YgdGhlIGRlc3RpbmF0aW9uIGNvdW50cnkuIFRoZXkgY292ZXIgcmVndWxhdGVkIG1vdmVtZW50cyBvZiBmb3JlaWduZXJzIGFzIHdlbGwgYXMgZnJlZSBtb3ZlbWVudCBtaWdyYXRpb24uIFRoZSBkYXRhIHByZXNlbnRlZCBhcmUgdGhlIHJlc3VsdCBvZiBhIHN0YW5kYXJkaXNhdGlvbiBwcm9jZXNzIHRoYXQgYWxsb3dzIGZvciBjcm9zcy1jb3VudHJ5IGNvbXBhcmlzb25zLiBUaGlzIGluZGljYXRvciBpcyBtZWFzdXJlZCBieSBudW1iZXJzIG9mIHBlcm1hbmVudCBpbmZsb3dzLgotIFN0b2NrcyBvZiBmb3JlaWduLWJvcm4gcG9wdWxhdGlvbiBpbiBPRUNEIGNvdW50cmllcwotIEZvcmVpZ24tYm9ybiBwb3B1bGF0aW9uCi0gRm9yZWlnbiBwb3B1bGF0aW9uCi0gTmF0aXZlLWJvcm4gZW1wbG95bWVudAotIEZvcmVpZ24tYm9ybiBlbXBsb3ltZW50Ci0gTmF0aXZlLWJvcm4gdW5lbXBsb3ltZW50Ci0gRm9yZWlnbi1ib3JuIHVuZW1wbG95bWVudAotIE5hdGl2ZS1ib3JuIHBhcnRpY2lwYXRpb24gcmF0ZXMKLSBGb3JlaWduLWJvcm4gcGFydGljaXBhdGlvbiByYXRlcwoKIyMjIFBlcm1hbmVudCBpbW1pZ3JhbnQgaW5mbG93cwoKUGVybWFuZW50IGltbWlncmFudCBpbmZsb3dzIFRvdGFsLCBOdW1iZXIsIDIwMjIgW0xpbmtdKGh0dHBzOi8vZGF0YS5vZWNkLm9yZy9taWdyYXRpb24vcGVybWFuZW50LWltbWlncmFudC1pbmZsb3dzLmh0bSkKCkRlZmluaXRpb24gb2YgUGVybWFuZW50IGltbWlncmFudCBpbmZsb3dzCgogIC0gUGVybWFuZW50IGltbWlncmFudCBpbmZsb3dzIGNvdmVyIHJlZ3VsYXRlZCBtb3ZlbWVudHMgb2YgZm9yZWlnbmVycyBjb25zaWRlcmVkIHRvIGJlIHNldHRsaW5nIGluIHRoZSBjb3VudHJ5IGZyb20gdGhlIHBlcnNwZWN0aXZlIG9mIHRoZSBkZXN0aW5hdGlvbiBjb3VudHJ5LiBUaGV5IGNvdmVyIHJlZ3VsYXRlZCBtb3ZlbWVudHMgb2YgZm9yZWlnbmVycyBhcyB3ZWxsIGFzIGZyZWUgbW92ZW1lbnQgbWlncmF0aW9uLiBUaGUgZGF0YSBwcmVzZW50ZWQgYXJlIHRoZSByZXN1bHQgb2YgYSBzdGFuZGFyZGlzYXRpb24gcHJvY2VzcyB0aGF0IGFsbG93cyBmb3IgY3Jvc3MtY291bnRyeSBjb21wYXJpc29ucy4gVGhpcyBpbmRpY2F0b3IgaXMgbWVhc3VyZWQgYnkgbnVtYmVycyBvZiBwZXJtYW5lbnQgaW5mbG93cy4KICAtIENpdGF0aW9uOiBPRUNEICgyMDI0KSwgUGVybWFuZW50IGltbWlncmFudCBpbmZsb3dzIChpbmRpY2F0b3IpLiBkb2k6IDEwLjE3ODcvMzA0NTQ2YjYtZW4gKEFjY2Vzc2VkIG9uIDI3IEphbnVhcnkgMjAyNCkKICAKCiMjIyBPRUNEOiBQZXJtYW5lbnQgaW1taWdyYW50IGluZmxvd3MKCiMjIyMgRGF0YSBJbmZvcm1hdGlvbgoKLSAgIERhdGEgU2l0ZTogaHR0cHM6Ly9kYXRhLm9lY2Qub3JnL21pZ3JhdGlvbi9wZXJtYW5lbnQtaW1taWdyYW50LWluZmxvd3MuaHRtCgotICAgRGVmaW5pdGlvbiBvZiBQZXJtYW5lbnQgaW1taWdyYW50IGluZmxvd3M6IApQZXJtYW5lbnQgaW1taWdyYW50IGluZmxvd3MgY292ZXIgcmVndWxhdGVkIG1vdmVtZW50cyBvZiBmb3JlaWduZXJzIGNvbnNpZGVyZWQgdG8gYmUgc2V0dGxpbmcgaW4gdGhlIGNvdW50cnkgZnJvbSB0aGUgcGVyc3BlY3RpdmUgb2YgdGhlIGRlc3RpbmF0aW9uIGNvdW50cnkuIFRoZXkgY292ZXIgcmVndWxhdGVkIG1vdmVtZW50cyBvZiBmb3JlaWduZXJzIGFzIHdlbGwgYXMgZnJlZSBtb3ZlbWVudCBtaWdyYXRpb24uIFRoZSBkYXRhIHByZXNlbnRlZCBhcmUgdGhlIHJlc3VsdCBvZiBhIHN0YW5kYXJkaXNhdGlvbiBwcm9jZXNzIHRoYXQgYWxsb3dzIGZvciBjcm9zcy1jb3VudHJ5IGNvbXBhcmlzb25zLiBUaGlzIGluZGljYXRvciBpcyBtZWFzdXJlZCBieSBudW1iZXJzIG9mIHBlcm1hbmVudCBpbmZsb3dzLgoKLSAgIENpdGF0aW9uOiBPRUNEICgyMDI0KSwgUGVybWFuZW50IGltbWlncmFudCBpbmZsb3dzIChpbmRpY2F0b3IpLiBkb2k6IDEwLjE3ODcvMzA0NTQ2YjYtZW4gKEFjY2Vzc2VkIG9uIDI4IEphbnVhcnkgMjAyNCkKCi0gICBDYXRlZ29yaWVzOiBUb3RhbCwgV29yaywgRnJlZSBtb3ZlbWVudHMsIEZhbWlseSwgRmFtaWx5IGFjY29tcGFueWluZyB3b3JrZXJzLCBIdW1hbml0YXJpYW4sIE90aGVyCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmBgYApSZWFkIHRoZSBkb3dubG9hZGVkIGZ1bGwgZGF0YSBvZiAnUGVybWFuZW50IEltbWlncmFudCBJbmZsb3dzJy4KCmBgYHtyfQpkZl9pbmZsb3dzIDwtIHJlYWRfY3N2KCJkYXRhL0RQX0xJVkVfMjgwMTIwMjQwMDQxMTcyNzkuY3N2IikKYGBgCmBgYHtyfQpkZl9pbmZsb3dzCmBgYAoKYGBge3J9CmRmX2luZmxvd3MgfD4gc2VsZWN0KC1WYWx1ZSkgfD4gbGFwcGx5KHVuaXF1ZSkKYGBgCgpTZXQgdGhlIG9yZGVyIG9mIGNhdGVnb3JpZXMgdG8gZGlzcGxheS4KCmBgYHtyfQpDQVQgPC0gYygiVE9UIiwgIldPUksiLCAiRlJFRU1PVlMiLCAiRkFNIiwgIkZBTVdPUktSIiwgIkhVTU5UUk4iLCAiT1RIIikKYGBgCgpBZGQgY291bnRyeSBuYW1lcyB1c2luZyB0aGUgYGNvdW50cnljb2RlYCBwYWNrYWdlIGFuZCBkZWxldGUgSU5ESUNBVE9SLCBNRUFTVVJFLCBGUkVRVUVOQ1ksIEZsYWcgQ29kZXMuCgpgYGB7cn0KZGZfaW4gPC0gZGZfaW5mbG93cyB8PiAKICBtdXRhdGUoY291bnRyeSA9IGNvdW50cnljb2RlKExPQ0FUSU9OLCAiaXNvM2MiLCAiY291bnRyeS5uYW1lIiksIC5iZWZvcmUgPSBMT0NBVElPTikgfD4gCiAgc2VsZWN0KGNvdW50cnksIGlzbzNjID0gTE9DQVRJT04sIGNhdGVnb3J5ID0gU1VCSkVDVCwgeWVhciA9IFRJTUUsIHZhbHVlID0gVmFsdWUpCmRmX2luCmBgYAoKYGBge3J9CmRmX2luIHw+IGZpbHRlcihjb3VudHJ5ID09ICJKYXBhbiIpIHw+IAogIGdncGxvdChhZXMoeWVhciwgdmFsdWUsIGNvbCA9IGZhY3RvcihjYXRlZ29yeSwgbGV2ZWxzID0gQ0FUKSkpICsgZ2VvbV9saW5lKCkgKyAKICBsYWJzKGNvbCA9ICJDYXRlZ29yaWVzIikKYGBgCgoKYGBge3J9CmRmX2luIHw+IGZpbHRlcihjb3VudHJ5ID09ICJKYXBhbiIpIHw+IGZpbHRlcihjYXRlZ29yeSAhPSAiVE9UIikgfD4gCiAgZ2dwbG90KGFlcyh5ZWFyLCB2YWx1ZSwgZmlsbCA9IGZhY3RvcihjYXRlZ29yeSwgbGV2ZWxzID0gcmV2KENBVCkpKSkgKyAKICBnZW9tX2FyZWEoY29sID0gImJsYWNrIiwgbGluZXdpZHRoID0gMC4xKSArCiAgbGFicyh0aXRsZSA9ICJQZXJtYW5lbnQgaW1taWdyYW50IGluZmxvd3Mgb2YgSmFwYW4iLCBmaWxsID0gIkNhdGVnb3JpZXMiKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTd9CmRmX2luIHw+IGZpbHRlcihjYXRlZ29yeSAhPSAiVE9UIikgfD4gCiAgZ2dwbG90KGFlcyh5ZWFyLCB2YWx1ZSwgZmlsbCA9IGZhY3RvcihjYXRlZ29yeSwgbGV2ZWxzID0gcmV2KENBVCkpKSkgKyBnZW9tX2FyZWEoY29sID0gImJsYWNrIiwgbGluZXdpZHRoID0gMC4xKSArCiAgZmFjZXRfd3JhcCh+Y291bnRyeSkgKyAKICBsYWJzKHRpdGxlID0gIlBlcm1hbmVudCBpbW1pZ3JhbnQgaW5mbG93cyBvZiAyOCBDb3VudHJpZXMiLCBmaWxsID0gIiIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnYm90dG9tJykKYGBgCgpgYGB7cn0KZGZfaW4gfD4gZmlsdGVyKGNvdW50cnkgJWluJSBjKCJHZXJtYW55IiwgIlVuaXRlZCBTdGF0ZXMiKSkgfD4gCiAgZ2dwbG90KGFlcyh5ZWFyLCB2YWx1ZSwgY29sID0gY291bnRyeSwgbGluZXR5cGUgPSBmYWN0b3IoY2F0ZWdvcnksIGxldmVscyA9IENBVCkpKSArIGdlb21fbGluZSgpICsKICBsYWJzKHRpdGxlID0gIlBlcm1hbmVudCBpbW1pZ3JhbnQgaW5mbG93cyBvZiBHZXJtYW55IGFuZCBVbml0ZWQgU3RhdGVzIiwgbGluZXR5cGUgPSAiQ2F0ZWdvcmllcyIpCmBgYAoKYGBge3IgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9N30KdG90X2xldiA8LSBkZl9pbiB8PiBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gY2F0ZWdvcnksIHZhbHVlc19mcm9tID0gdmFsdWUpIHw+IAogIHBpdm90X2xvbmdlcihjb2xzID0gQ0FUW0NBVCE9IlRPVCJdLCBuYW1lc190byA9ICJjYXRlZ29yeSIsIHZhbHVlc190byA9ICJ2YWx1ZSIpIHw+IGZpbHRlcih5ZWFyID09IDIwMjIpIHw+IGRpc3RpbmN0KGNvdW50cnksIGlzbzNjLCBUT1QpIHw+IGFycmFuZ2UoZGVzYyhUT1QpKSB8PiBwdWxsKGNvdW50cnkpCmRmX2luIHw+IHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBjYXRlZ29yeSwgdmFsdWVzX2Zyb20gPSB2YWx1ZSkgfD4gCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBDQVRbQ0FUIT0iVE9UIl0sIG5hbWVzX3RvID0gImNhdGVnb3J5IiwgdmFsdWVzX3RvID0gInZhbHVlIikgfD4gZmlsdGVyKHllYXIgPT0gMjAyMikgfD4gZ2dwbG90KGFlcyhmYWN0b3IoY291bnRyeSwgbGV2ZWxzID0gcmV2KHRvdF9sZXYpKSwgdmFsdWUsIGZpbGwgPSBmYWN0b3IoY2F0ZWdvcnksIGxldmVscyA9IENBVCkpKSArIGdlb21fY29sKGNvbCA9ICJibGFjayIsIGxpbmV3aWR0aCA9IDAuMSkgKyBjb29yZF9mbGlwKCkgKwogIGxhYnModGl0bGUgPSAiUGVybWFuZW50IGltbWlncmFudCBpbmZsb3dzIGluIDIwMjIiLCBmaWxsID0gIiIsIHggPSAiIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdib3R0b20nKQpgYGAKCgojIyMgT0VDRDogRm9yZWlnbiBwb3B1bGF0aW9uCgojIyMjIERhdGEgSW5mb3JtYXRpb24KCi0gICBEYXRhIFNpdGU6IGh0dHBzOi8vZGF0YS5vZWNkLm9yZy9taWdyYXRpb24vZm9yZWlnbi1wb3B1bGF0aW9uLmh0bQoKLSAgIERlZmluaXRpb24gb2YgRm9yZWlnbiBwb3B1bGF0aW9uOiAKVGhlIGZvcmVpZ24gcG9wdWxhdGlvbiBjb25zaXN0cyBvZiBwZW9wbGUgd2hvIHN0aWxsIGhhdmUgdGhlIG5hdGlvbmFsaXR5IG9mIHRoZWlyIGhvbWUgY291bnRyeS4gSXQgbWF5IGluY2x1ZGUgcGVvcGxlIGJvcm4gaW4gdGhlIGhvc3QgY291bnRyeS4gVGhlIGRpZmZlcmVuY2UgYWNyb3NzIGNvdW50cmllcyBiZXR3ZWVuIHRoZSBzaXplIG9mIHRoZSBmb3JlaWduLWJvcm4gcG9wdWxhdGlvbiBhbmQgdGhhdCBvZiB0aGUgZm9yZWlnbiBwb3B1bGF0aW9uIGRlcGVuZHMgb24gdGhlIHJ1bGVzIGdvdmVybmluZyB0aGUgYWNxdWlzaXRpb24gb2YgY2l0aXplbnNoaXAgaW4gZWFjaCBjb3VudHJ5LiBUaGlzIGluZGljYXRvciBpcyBtZWFzdXJlZCBhcyBhIHBlcmNlbnRhZ2Ugb2YgcG9wdWxhdGlvbi4KCi0gICBDaXRhdGlvbjogT0VDRCAoMjAyNCksIEZvcmVpZ24gcG9wdWxhdGlvbiAoaW5kaWNhdG9yKS4gZG9pOiAxMC4xNzg3LzE2YTkxNGUzLWVuIChBY2Nlc3NlZCBvbiAyOCBKYW51YXJ5IDIwMjQpCgotICAgQ2F0ZWdvcmllczogVG90YWwsIFBlcmNlbnQgb2YgUG9wdWxhdGlvbgoKUmVhZCB0aGUgZG93bmxvYWRlZCBmdWxsIGRhdGEgb2YgJ0ZvcmVpZ24gcG9wdWxhdGlvbicuCgpgYGB7cn0KZGZfZm9yZWlnbiA8LSByZWFkX2NzdigiZGF0YS9EUF9MSVZFXzI4MDEyMDI0MDA0MjAwMTI0LmNzdiIpCmBgYApgYGB7cn0KZGZfZm9yZWlnbgpgYGAKCmBgYHtyfQpkZl9mb3JlaWduIHw+IHNlbGVjdCgtVmFsdWUpIHw+IGxhcHBseSh1bmlxdWUpCmBgYAoKQWRkIGNvdW50cnkgbmFtZXMgdXNpbmcgdGhlIGBjb3VudHJ5Y29kZWAgcGFja2FnZSBhbmQgZGVsZXRlIElORElDQVRPUiwgTUVBU1VSRSwgRlJFUVVFTkNZLCBGbGFnIENvZGVzLgoKYGBge3J9CmRmX2Zwb3AgPC0gZGZfZm9yZWlnbiB8PiAKICBtdXRhdGUoY291bnRyeSA9IGNvdW50cnljb2RlKExPQ0FUSU9OLCAiaXNvM2MiLCAiY291bnRyeS5uYW1lIiksIC5iZWZvcmUgPSBMT0NBVElPTikgfD4gCiAgc2VsZWN0KGNvdW50cnksIGlzbzNjID0gTE9DQVRJT04sIHllYXIgPSBUSU1FLCBmb3JlaWduID0gVmFsdWUpCmRmX2Zwb3AKYGBgCgpgYGB7cn0KZGZfZnBvcCB8PiBmaWx0ZXIoY291bnRyeSA9PSAiSmFwYW4iKSB8PiAKICBnZ3Bsb3QoYWVzKHllYXIsIGZvcmVpZ24pKSArIGdlb21fbGluZSgpICsgCiAgbGFicyh0aXRsZSA9ICJGb3JlaWduIFBvcHVsYXRpb24gaW4gSmFwYW4gKFBlcmNlbnQpIikKYGBgCgoKYGBge3J9CmRmX2Zwb3AgfD4gCiAgZ2dwbG90KGFlcyh5ZWFyLCBmb3JlaWduKSkgKyBnZW9tX2xpbmUoYWVzKGNvbCA9IGlzbzNjKSkgKyAKICBnZW9tX3Ntb290aChmb3JtdWxhID0gJ3l+eCcsIG1ldGhvZCA9ICJsb2VzcyIsIHNlID0gRkFMU0UpICsgCiAgbGFicyh0aXRsZSA9ICJUb3RhbCBGb3JlaWduIFBvcHVsYXRpb24gKCUpIikKYGBgCgpgYGB7cn0KZGZfZnBvcCB8PiBmaWx0ZXIoeWVhciA9PSAyMDE5KSB8PiAKICBnZ3Bsb3QoYWVzKGZjdF9yZW9yZGVyKGNvdW50cnksIGZvcmVpZ24pLCBmb3JlaWduKSkgKyBnZW9tX2NvbCgpICsgCiAgY29vcmRfZmxpcCgpICsgbGFicyh0aXRsZSA9ICJGb3JlaWduIFBvcHVsYXRpb24gKCUpIiwgeCA9ICIiLCB5ID0gIiIpCmBgYAoKCgojIyMgT0VDRDogUG9wdWxhdGlvblRvdGFsLCBNaWxsaW9uIHBlcnNvbnMsIDIwMjIgb3IgbGF0ZXN0IGF2YWlsYWJsZQoKIyMjIyBEYXRhIEluZm9ybWF0aW9uCgotICAgRGF0YSBTaXRlOiBodHRwczovL2RhdGEub2VjZC5vcmcvcG9wL3BvcHVsYXRpb24uaHRtCgotICAgRGVmaW5pdGlvbiBvZiBQb3B1bGF0aW9uOiBQb3B1bGF0aW9uIGlzIGRlZmluZWQgYXMgYWxsIG5hdGlvbmFscyBwcmVzZW50IGluLCBvciB0ZW1wb3JhcmlseSBhYnNlbnQgZnJvbSBhIGNvdW50cnksIGFuZCBhbGllbnMgcGVybWFuZW50bHkgc2V0dGxlZCBpbiBhIGNvdW50cnkuIFRoaXMgaW5kaWNhdG9yIHNob3dzIHRoZSBudW1iZXIgb2YgcGVvcGxlIHRoYXQgdXN1YWxseSBsaXZlIGluIGFuIGFyZWEuIEdyb3d0aCByYXRlcyBhcmUgdGhlIGFubnVhbCBjaGFuZ2VzIGluIHBvcHVsYXRpb24gcmVzdWx0aW5nIGZyb20gYmlydGhzLCBkZWF0aHMgYW5kIG5ldCBtaWdyYXRpb24gZHVyaW5nIHRoZSB5ZWFyLiBUb3RhbCBwb3B1bGF0aW9uIGluY2x1ZGVzIHRoZSBmb2xsb3dpbmc6IG5hdGlvbmFsIGFybWVkIGZvcmNlcyBzdGF0aW9uZWQgYWJyb2FkOyBtZXJjaGFudCBzZWFtZW4gYXQgc2VhOyBkaXBsb21hdGljIHBlcnNvbm5lbCBsb2NhdGVkIGFicm9hZDsgY2l2aWxpYW4gYWxpZW5zIHJlc2lkZW50IGluIHRoZSBjb3VudHJ5OyBkaXNwbGFjZWQgcGVyc29ucyByZXNpZGVudCBpbiB0aGUgY291bnRyeS4gSG93ZXZlciwgaXQgZXhjbHVkZXMgdGhlIGZvbGxvd2luZzogZm9yZWlnbiBhcm1lZCBmb3JjZXMgc3RhdGlvbmVkIGluIHRoZSBjb3VudHJ5OyBmb3JlaWduIGRpcGxvbWF0aWMgcGVyc29ubmVsIGxvY2F0ZWQgaW4gdGhlIGNvdW50cnk7IGNpdmlsaWFuIGFsaWVucyB0ZW1wb3JhcmlseSBpbiB0aGUgY291bnRyeS4gUG9wdWxhdGlvbiBwcm9qZWN0aW9ucyBhcmUgYSBjb21tb24gZGVtb2dyYXBoaWMgdG9vbC4gVGhleSBwcm92aWRlIGEgYmFzaXMgZm9yIG90aGVyIHN0YXRpc3RpY2FsIHByb2plY3Rpb25zLCBoZWxwaW5nIGdvdmVybm1lbnRzIGluIHRoZWlyIGRlY2lzaW9uIG1ha2luZy4gVGhpcyBpbmRpY2F0b3IgaXMgbWVhc3VyZWQgaW4gdGVybXMgb2YgYW5udWFsIGdyb3d0aCByYXRlIGFuZCBpbiB0aG91c2FuZHMgb2YgcGVvcGxlLgoKICAtIENpdGF0aW9uOiBPRUNEICgyMDI0KSwgUG9wdWxhdGlvbiAoaW5kaWNhdG9yKS4gZG9pOiAxMC4xNzg3L2Q0MzRmODJiLWVuIChBY2Nlc3NlZCBvbiAyOCBKYW51YXJ5IDIwMjQpCgpgYGB7cn0KZGZfb2VjZF9wb3AgPC0gcmVhZF9jc3YoImRhdGEvRFBfTElWRV8yODAxMjAyNDA2NDAwMjk1Ny5jc3YiKQpkZl9vZWNkX3BvcApgYGAKCmBgYHtyfQpkZl9vZWNkX3BvcCB8PiBzZWxlY3QoLVZhbHVlKSB8PiBsYXBwbHkodW5pcXVlKQpgYGAKCmBgYHtyfQpkZl9wb3Bfc2hvcnQgPC0gZGZfb2VjZF9wb3AgfD4gZmlsdGVyKFNVQkpFQ1QgPT0gIlRPVCIpIHw+IHNlbGVjdChpc28zYyA9IExPQ0FUSU9OLCB5ZWFyID0gVElNRSwgcG9wID0gVmFsdWUpCmBgYAoKCiMjIyBDb21iaW5lIFRocmVlIERhdGFzZXRzIG9mIE9FQ0QKCkNoZWNrIHRoZSBkaWZmZXJlbmNlcyBvZiBjb3VudHJpZXMgaW4gZWFjaCBkYXRhc2V0cy4KCmBgYHtyfQpzZXRkaWZmKGRmX2Zwb3AkaXNvM2MsIGRmX2luJGlzbzNjKTsgc2V0ZGlmZihkZl9pbiRpc28zYyxkZl9mcG9wJGlzbzNjKQpzZXRkaWZmKGRmX2Zwb3AkaXNvM2MsIGRmX3BvcF9zaG9ydCRpc28zYyk7IHNldGRpZmYoZGZfaW4kaXNvM2MsIGRmX3BvcF9zaG9ydCRpc28zYykKYGBgCgoqICJIVU4iICJTVksiICJTVk4iICJHUkMiICJJU0wiICJUVVIiICJDSEwiICJMVkEiICJMVFUiIGFyZSBpbiBgZGZfZnBvcGAgYnV0IG5vdCBpbiBgZGZfaW5gLgoqICJBVVMiICJOWkwiICJJU1IiICJSVVMiIGFyZSBpbiBgZGZfaW5gIGJ1dCBub3QgaW4gYGRmX2Zwb3BgLgoqIGBkZl9wb3Bfc2hvcnRgIGNvbnRhaW5zIHRoZSBkYXRhIG9mIGNvdW50cmllcyBpbiBgZGZfaW5gIGFuZCBgZGZfZnBvcGAuCgpgYGB7cn0KZGZfZnBvcDIgPC0gZGZfZnBvcCB8PiBzZWxlY3QoaXNvM2MsIHllYXIsIGZvcmVpZ24pCmRmX29lY2RfZnBvcCA8LSBkZl9pbiB8PiBmdWxsX2pvaW4oZGZfZnBvcDIsIGJ5ID0gYygiaXNvM2MiLCAieWVhciIpKSB8PgogIGxlZnRfam9pbihkZl9wb3Bfc2hvcnQsIGJ5ID0gYygiaXNvM2MiLCAieWVhciIpKSB8PgogIG11dGF0ZShmb3JlaWduX3BvcCA9IHJvdW5kKHBvcCoxMDAwMCpmb3JlaWduKSwgLmFmdGVyID0gdmFsdWUpCmRmX29lY2RfZnBvcApgYGAKCmBgYHtyfQpkZl9vZWNkX2Zwb3AgfD4gZmlsdGVyKGNhdGVnb3J5ID09ICJUT1QiKSB8PiBkcm9wX25hKHZhbHVlLCBmb3JlaWduKSB8PgogIGZpbHRlcih2YWx1ZSA+MCwgZm9yZWlnbiA+MCkgfD4KICBnZ3Bsb3QoYWVzKHZhbHVlLCBmb3JlaWduX3BvcCkpICsgZ2VvbV9wb2ludChhZXMoY29sID0gaXNvM2MpKSArIHNjYWxlX3hfbG9nMTAoKSArIHNjYWxlX3lfbG9nMTAoKSArIGdlb21fc21vb3RoKGZvcm11bGEgPSAneX54JywgbWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSkKYGBgCgojIyBVTmRhdGEgLSBhIHdvcmxkIG9mIGluZm9ybWF0aW9uCgo8aHR0cHM6Ly9kYXRhLnVuLm9yZy8+CgpQb3B1bGFyIHN0YXRpc3RpY2FsIHRhYmxlcwoKRXhwbG9yZXIgLSBkYXRhbWFydHM6IDxodHRwOi8vZGF0YS51bi5vcmcvRXhwbG9yZXIuYXNweD4KCi0gICBEYXRhc2V0cywgU291cmNlcywgVG9waWNzCgojIyMgUG9wdWxhciBzdGF0aXN0aWNhbCB0YWJsZXMKCkNvcHkgdGhlIGxpbmsgb2YgSW50ZXJuYXRpb25hbCBNaWdyYW50cyBhbmQgUmVmdWdlZXMKCmBgYHtyfQp1bl9taWdyYW50c191cmwgPC0gImh0dHBzOi8vZGF0YS51bi5vcmcvX0RvY3MvU1lCL0NTVi9TWUI2Nl8zMjdfMjAyMzEwX0ludGVybmF0aW9uYWwlMjBNaWdyYW50cyUyMGFuZCUyMFJlZnVnZWVzLmNzdiIKZG93bmxvYWQuZmlsZSh1bl9taWdyYW50c191cmwsIGRlc3RmaWxlID0gImRhdGEvbWlncmFudHMuY3N2IikKYGBgCgpgYGB7cn0KZGZfdW5fbWlncmFudHMgPC0gcmVhZF9jc3YoImRhdGEvbWlncmFudHMuY3N2IikKZGZfdW5fbWlncmFudHMKYGBgCgpgYGB7cn0KZGZfdW5fbWlncmFudHMgPC0gcmVhZF9jc3YoImRhdGEvbWlncmFudHMuY3N2Iiwgc2tpcD0xKQpkZl91bl9taWdyYW50cwpgYGAKCmBgYHtyfQpzdHIoZGZfdW5fbWlncmFudHMpCmBgYAoKCmBgYHtyfQpkZl91bl9taWdyYW50cyB8PiBzdW1tYXJ5KCkKYGBgCgpgYGB7cn0KZGZfdW5fbWlncmFudHMgfD4gc2VsZWN0KFllYXIsU2VyaWVzKSB8PiBsYXBwbHkodW5pcXVlKQpgYGAKCmBgYHtyIGV2YWwgPSBGQUxTRX0KZGZfdW5fbWlncmFudHMgfD4gZGlzdGluY3QoYFJlZ2lvbi9Db3VudHJ5L0FyZWFgLCAuLi4yKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KGNvdW50cnljb2RlKQpkZl91bl9taWdyYW50cyAlPiUgbXV0YXRlKGlzbzNjID0gY291bnRyeWNvZGUoYFJlZ2lvbi9Db3VudHJ5L0FyZWFgLCAidW4iLCAiaXNvM2MiKSwgLmFmdGVyID0gLi4uMikKYGBgCgpgYGB7cn0KZGZfdW5fbWlncmFudHMgfD4gbXV0YXRlKGlzbzNjID0gY291bnRyeWNvZGUoYFJlZ2lvbi9Db3VudHJ5L0FyZWFgLCAidW4iLCAiaXNvM2MiKSwgLmFmdGVyID0gLi4uMikgfD4gZmlsdGVyKGlzLm5hKGlzbzNjKSkgfD4gZGlzdGluY3QoLi4uMikKYGBgCgpgYGB7cn0Kd2RpY2FjaGUgPC0gcmVhZF9yZHMoImRhdGEvd2RpY2FjaGUucmRzIikKd2RpX2NvdW50cnlfZXh0cmEgPC0gd2RpY2FjaGUkY291bnRyeSB8PiBzZWxlY3QoaXNvM2MsIHJlZ2lvbiwgaW5jb21lLCBsZW5kaW5nKQpgYGAKCmBgYHtyIGV2YWw9RkFMU0V9CmRmX3VuX21pZ3JhbnRzX2V4dCA8LSBkZl91bl9taWdyYW50cyB8PgogIG11dGF0ZShpc28zYyA9IGNvdW50cnljb2RlKGBSZWdpb24vQ291bnRyeS9BcmVhYCwgInVuIiwgImlzbzNjIiksIC5hZnRlciA9IC4uLjIpIHw+CiAgc2VsZWN0KGNvdW50cnkgPSAuLi4yLCBpc28zYywgeWVhciA9IFllYXIsIHNlcmllcyA9IFNlcmllcywgdmFsdWUgPSBWYWx1ZSwgZm9vdG5vdGVzID0gRm9vdG5vdGVzKSB8PgogIGxlZnRfam9pbih3ZGlfY291bnRyeV9leHRyYSwgYnkgPSAiaXNvM2MiKQpkZl91bl9taWdyYW50c19leHQKYGBgCgpgYGB7ciBlY2hvPUZBTFNFfQpkZl91bl9taWdyYW50c19leHQgPC0gZGZfdW5fbWlncmFudHMgJT4lIAogIG11dGF0ZShpc28zYyA9IGNvdW50cnljb2RlKGBSZWdpb24vQ291bnRyeS9BcmVhYCwgInVuIiwgImlzbzNjIiksIC5hZnRlciA9IC4uLjIpIHw+CiAgc2VsZWN0KGNvdW50cnkgPSAuLi4yLCBpc28zYywgeWVhciA9IFllYXIsIFNlcmllcywgbWlncmFudHMgPSBWYWx1ZSwgRm9vdG5vdGVzKSB8PgogIGxlZnRfam9pbih3ZGlfY291bnRyeV9leHRyYSwgYnkgPSAiaXNvM2MiKQpkZl91bl9taWdyYW50c19leHQKYGBgCgpgYGB7cn0KZGZfdW5fbWlncmFudHNfZXh0JFNlcmllcyB8PiB1bmlxdWUoKQpgYGAKCmBgYHtyfQpkZl91bl9taWdyYW50c19leHRfcmV2IDwtIGRmX3VuX21pZ3JhbnRzX2V4dCB8PiBtdXRhdGUoc2VyID0gY2FzZV93aGVuKAogIFNlcmllcyA9PSAiSW50ZXJuYXRpb25hbCBtaWdyYW50IHN0b2NrOiBCb3RoIHNleGVzIChudW1iZXIpIiB+ICJtaWdyYW50IiwKICBTZXJpZXMgPT0gIkludGVybmF0aW9uYWwgbWlncmFudCBzdG9jazogQm90aCBzZXhlcyAoJSB0b3RhbCBwb3B1bGF0aW9uKSIgfiAibWlncmFudF9wZXJjZW50IiwKICBTZXJpZXMgPT0gIkludGVybmF0aW9uYWwgbWlncmFudCBzdG9jazogTWFsZSAoJSB0b3RhbCBQb3B1bGF0aW9uKSIgfiAibWlncmFudF9tYWxlIiwKICBTZXJpZXMgPT0gIkludGVybmF0aW9uYWwgbWlncmFudCBzdG9jazogRmVtYWxlICglIHRvdGFsIFBvcHVsYXRpb24pIiB+ICJtaWdyYW50X2ZlbWFsZSIsCiAgU2VyaWVzID09ICJUb3RhbCByZWZ1Z2VlcyBhbmQgcGVvcGxlIGluIHJlZnVnZWUtbGlrZSBzaXR1YXRpb25zIChudW1iZXIpIiB+ICJyZWZ1Z2VlIiwKICBTZXJpZXMgPT0gIkFzeWx1bSBzZWVrZXJzLCBpbmNsdWRpbmcgcGVuZGluZyBjYXNlcyAobnVtYmVyKSIgfiAiYXN5bHVtIiwKICBTZXJpZXMgPT0gIk90aGVyIG9mIGNvbmNlcm4gdG8gVU5IQ1IgKG51bWJlcikiICB+ICJvdGhlciIsCiAgU2VyaWVzID09ICJUb3RhbCBwb3B1bGF0aW9uIG9mIGNvbmNlcm4gdG8gVU5IQ1IgKG51bWJlcikiIH4gImNvbmNlcm4iLAogIFRSVUUgfiBTZXJpZXMpLCAuYmVmb3JlID0gU2VyaWVzKQpgYGAKCmBgYHtyfQpkZl91bl9taWdyYW50c19leHRfcmV2CmBgYAoKYGBge3J9CmRmX3VuX21pZ3JhbnRzX2V4dF9yZXYgfD4gZmlsdGVyKGNvdW50cnkgJWluJSBjKCJUb3RhbCwgYWxsIGNvdW50cmllcyBvciBhcmVhcyIsICJBZnJpY2EiLCAiQXNpYSIsICJFdXJvcGUiLCAiTGF0aW4gQW1lcmljYSIsICJPY2VhbmlhIikpIHw+CiAgZ2dwbG90KGFlcyh5ZWFyLCBtaWdyYW50cywgY29sID0gc2VyLCBsaW5ldHlwZSA9IGNvdW50cnkpKSArIGdlb21fbGluZSgpCmBgYAoKYGBge3J9CmRmX3VuX21pZ3JhbnRzX2V4dF9yZXYgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCkgfD4gI2ZpbHRlcihzZXIgPT0gInJlZnVnZWUiKSB8PgogIGZpbHRlcihjb3VudHJ5ICVpbiUgYygiVG90YWwsIGFsbCBjb3VudHJpZXMgb3IgYXJlYXMiLCAiQWZyaWNhIiwgIkFzaWEiLCAiRXVyb3BlIiwgIkxhdGluIEFtZXJpY2EiLCAiT2NlYW5pYSIpKSB8PiBzZWxlY3QoLWMoaXNvM2MsIFNlcmllcywgRm9vdG5vdGVzLCByZWdpb24sIGluY29tZSwgbGVuZGluZykpCmBgYAoKYGBge3J9CmRmX3VuX21pZ3JhbnRzX2V4dF9yZXYgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCkgfD4gZmlsdGVyKCEoc2VyICVpbiUgYygibWlncmFudF9tYWxlIiwgIm1pZ3JhbnRfZmVtYWxlIiwgIm1pZ3JhbnRfcGVyY2VudCIpKSkgfD4gZmlsdGVyKGNvdW50cnkgJWluJSBjKCJBZnJpY2EiLCAiQXNpYSIsICJFdXJvcGUiLCAiTGF0aW4gQW1lcmljYSIsICJPY2VhbmlhIikpIHw+IGdncGxvdChhZXMoY291bnRyeSwgbWlncmFudHMsIGZpbGwgPSBzZXIpKSArIGdlb21fY29sKGNvbCA9ICJibGFjayIsIGxpbmV3aWR0aCA9IDAuMSkKYGBgCgoKIyMjIEpvaW4gT0VDRCBEYXRhIHdpdGggVU4gRGF0YQoKYGBge3J9CmRmX29lY2RfdW4gPC0gZGZfb2VjZF9mcG9wIHw+IGxlZnRfam9pbihkZl91bl9taWdyYW50c19leHRfcmV2LCBieSA9IGMoImNvdW50cnkiLCAiaXNvM2MiLCAieWVhciIpKSB8PgogIHNlbGVjdChjb3VudHJ5LCBpc28zYywgY2F0ZWdvcnksIHllYXIsIHZhbHVlLCBmb3JlaWduX3BvcCwgZm9yZWlnbiwgcG9wLCBzZXIsIG1pZ3JhbnRzKQpkZl9vZWNkX3VuCmBgYAoKYGBge3J9CmRmX29lY2RfdW4gfD4gZmlsdGVyKGNvdW50cnkgPT0gIkphcGFuIikKYGBgCgpgYGB7cn0KZGZfb2VjZF91bl93aWRlIDwtIGRmX29lY2RfdW4gfD4gZHJvcF9uYSh2YWx1ZSwgbWlncmFudHMpIHw+IHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBjYXRlZ29yeSwgdmFsdWVzX2Zyb20gPSB2YWx1ZSkgIHw+CiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHNlciwgdmFsdWVzX2Zyb20gPSBtaWdyYW50cykKZGZfb2VjZF91bl93aWRlCmBgYAoKCg==